//
//  MBCryptor.m
//  mobion Music
//
//  Created by Vu Manh Hung on 12/28/10.
//  Copyright 2010 GNT. All rights reserved.
//

#import "Cryptor.h"
#import "NSDataAdditions.h"
#import <CommonCrypto/CommonHMAC.h>
#include "Base64Transcoder.h"

@implementation Cryptor

@synthesize key = _key;

- (id)initWithKey:(NSString *)aKey 
{
	self = [super init];
	if (self) 
    {
		self.key = aKey;		
	}
	return self;
}

- (NSString *)encrypt:(NSString *)data 
{
    
    size_t plainTextBufferSize = [data length];
    const void *vplainText = [data UTF8String];
    
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;
    
    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t));
    memset(bufferPtr, 0x0, bufferPtrSize);
    
    NSString *initVec = @"init Vec";
    const void *vkey = [self.key UTF8String];
    const void *vinitVec = [initVec UTF8String];
    
    CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt,
                                       kCCAlgorithmDES,
                                       kCCOptionPKCS7Padding,
                                       vkey,
                                       kCCKeySizeDES,
                                       vinitVec,
                                       vplainText,
                                       plainTextBufferSize,
                                       bufferPtr,
                                       bufferPtrSize,
                                       &movedBytes);
    if (ccStatus != 0)
    {
		return nil;
	}
    
    NSData *myData = [NSData dataWithBytes:bufferPtr length:movedBytes];
    NSString *result = [myData base64Encoding];
    free(bufferPtr);
    return result;
}


- (NSString *)decrypt:(NSString *)data 
{
    
    NSData *encryptedData = [[NSData alloc] initWithBase64EncodedString:data];
    size_t plainTextBufferSize = [encryptedData length];
    const void *vplainText = [encryptedData bytes];
	
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;
    
    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    memset(bufferPtr, 0x0, bufferPtrSize);
    
    NSString *initVec = @"init Vec";
    const void *vkey = [self.key UTF8String];
    const void *vinitVec = [initVec UTF8String];
    
    CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
                                       kCCAlgorithmDES,
                                       kCCOptionPKCS7Padding,
                                       vkey,
                                       kCCKeySizeDES,
                                       vinitVec,
                                       vplainText,
                                       plainTextBufferSize,
                                       bufferPtr,
                                       bufferPtrSize,
                                       &movedBytes);
    
    [encryptedData release];
    
    if (ccStatus != 0) 
    {
		return nil;
	}
    
    NSString *decString = [[[NSString alloc] initWithData:[NSData dataWithBytes:bufferPtr 
                                                                         length:movedBytes] 
                                                 encoding:NSASCIIStringEncoding] autorelease];
    free(bufferPtr);
    return decString;
}


- (NSData *)encryptData:(NSData *)data
{
    if (!data)
        return nil;
    size_t plainTextBufferSize = [data length];
    const void *vplainText = [data bytes];
    
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;
    
    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t));    
    if (bufferPtr == NULL)
        goto encrypt_error;
    
    memset(bufferPtr, 0x0, bufferPtrSize);
    
    NSString *initVec = @"init Vec";
    const void *vkey = [self.key UTF8String];
    const void *vinitVec = [initVec UTF8String];
    
    CCCryptorStatus ccStatus = CCCrypt(kCCEncrypt,
                                       kCCAlgorithmDES,
                                       kCCOptionPKCS7Padding,
                                       vkey,
                                       kCCKeySizeDES,
                                       vinitVec,
                                       vplainText,
                                       plainTextBufferSize,
                                       bufferPtr,
                                       bufferPtrSize,
                                       &movedBytes);
    if (ccStatus != 0)
		goto encrypt_error;
    
    NSData *myData = [[NSData alloc] initWithBytes:bufferPtr length:movedBytes];
    if (bufferPtr) 
    {
        free(bufferPtr);
        bufferPtr = nil;
    }
    
    return [myData autorelease];
    
encrypt_error:
    if (bufferPtr) 
    {
        free(bufferPtr);
        bufferPtr = NULL;
    }
    return nil;
}

- (NSData *)decryptData:(NSData *)encryptedData
{
    if (!encryptedData)
        return nil;
    size_t plainTextBufferSize = [encryptedData length];
    const void *vplainText = [encryptedData bytes];
	
    uint8_t *bufferPtr = NULL;
    size_t bufferPtrSize = 0;
    size_t movedBytes = 0;
    
    bufferPtrSize = (plainTextBufferSize + kCCBlockSizeDES) & ~(kCCBlockSizeDES - 1);
    bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
    if (bufferPtr == NULL)
        goto decrypt_error;        
    memset(bufferPtr, 0x0, bufferPtrSize);
    
    NSString *initVec = @"init Vec";
    const void *vkey = [self.key UTF8String];
    const void *vinitVec = [initVec UTF8String];
    
    CCCryptorStatus ccStatus = CCCrypt(kCCDecrypt,
                                       kCCAlgorithmDES,
                                       kCCOptionPKCS7Padding,
                                       vkey,
                                       kCCKeySizeDES,
                                       vinitVec,
                                       vplainText,
                                       plainTextBufferSize,
                                       bufferPtr,
                                       bufferPtrSize,
                                       &movedBytes);
    
    if (ccStatus != 0)
		goto decrypt_error;	
    
    NSData *myData = [[NSData alloc] initWithBytes:bufferPtr length:movedBytes];
    
    if (bufferPtr) 
    {
        free(bufferPtr);
        bufferPtr = NULL;
    }
    
    return [myData autorelease];
    
decrypt_error:
    if (bufferPtr)
    {
        free(bufferPtr);
        bufferPtr = NULL;
    }
    return nil;
}

// KHOAINM
+ (NSString *)encryptedMessage:(NSString *)text byKey:(NSString *)key
{
    NSData *secretData = [key dataUsingEncoding:NSUTF8StringEncoding];
    NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding];
    unsigned char result[20];
	
    CCHmac(kCCHmacAlgSHA1, [secretData bytes], [secretData length], [clearTextData bytes], [clearTextData length], result);
    
    char base64Result[32];
    size_t theResultLength = 32;
    Base64EncodeData(result, 20, base64Result, &theResultLength);
    NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength];
    
    NSString *base64EncodedResult = [[[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding] autorelease];
    
    return base64EncodedResult;
}

- (void)dealloc
{
    [_key release];
    [super dealloc];
}

@end
